package boundary;

import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Font;
import java.awt.Graphics;
import java.awt.GridLayout;
import java.awt.Image;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;

import javax.swing.JApplet;
import javax.swing.JCheckBox;
import javax.swing.JComboBox;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.JSlider;
import javax.swing.JTextField;
import javax.swing.border.EmptyBorder;
import javax.swing.event.ChangeEvent;
import javax.swing.event.ChangeListener;

import model.NormalTaskUtility;
import model.SmartTaskUtility;
import model.taskQueueUtility;
import taskGenerator.TaskGenerator;
import util.IniParameters;
import controls.CenterTimer;
import controls.ElevatorControl;
import controls.Refreshable;

public final class MainJApplet extends JApplet implements Refreshable {
	private static final long serialVersionUID = 1L;
	private final Color topPanelBgColor = new Color(247, 247, 247);
	private final Color inputBarBgColor = new Color(247, 247, 247);
	private final Color mainBgColor = new Color(247, 247, 247);

	/**
	 * Part 1: for control
	 */
	private final int m_nFloors = IniParameters.numberOfFloors;
	private CenterTimer m_centerTimer = CenterTimer.getInstance();
	private TaskGenerator m_taskGenerator;

	private ElevatorControl m_leftElevator;
	private SmartTaskUtility m_leftTasks;

	private ElevatorControl m_rightElevator;
	private NormalTaskUtility m_rightTasks;
	private taskQueueUtility m_rightTaskQueueUtility;

	public void start() {
		// initialize association classes
		m_centerTimer = CenterTimer.getInstance();
		m_centerTimer.addToControlRefreshList(this);
		m_centerTimer.startTimer();

		m_leftTasks = new SmartTaskUtility();
		m_leftElevator = new ElevatorControl(m_leftTasks, true);

		m_rightTasks = new NormalTaskUtility();
		m_rightElevator = new ElevatorControl(m_rightTasks, false);
		m_rightTaskQueueUtility = new taskQueueUtility(m_rightTasks);

		m_taskGenerator = new TaskGenerator(m_leftTasks,
				m_rightTaskQueueUtility);

		// initialize JApplet
		iniTheJApplet();		
		
	}

	public void stop() {
		m_centerTimer.stopTimer();
	}

	public void refresh() {
		repaint();
	}

	/**
	 * Part 2: for drawing JApplet
	 */
	// window parameters
	private final int m_appletWidth = IniParameters.appletWidth;
	private final int m_appletHeight = IniParameters.appletHeight;
	private final int m_leftWidth = IniParameters.leftPartWidth;
	private final int m_inputBarWidth = IniParameters.inputBarWidth;
	private final int m_rightWidth = IniParameters.rightPartWidth;
	private final int m_topPanelHeight = IniParameters.topPanelHeight;
	private final int m_marginBottom = IniParameters.marginBottom;

	// for double buffering
	private Graphics m_bufferGraphics;
	private Image m_offscreen;

	// assistant drawing classes
	private LeftPartDrawer _leftPartDrawer = new LeftPartDrawer();
	private RightPartDrawer _rightPartDrawer = new RightPartDrawer();

	private JPanel m_leftPanel = new JPanel();
	private JPanel m_rightPanel = new JPanel();

	private void iniTheJApplet() {
		// initialize parameters for double buffer
		m_offscreen = createImage(m_appletWidth, m_appletHeight);
		m_bufferGraphics = m_offscreen.getGraphics();

		// initialize the layout
		setLayout(new BorderLayout());

		// initialize top panel
		iniTopPanel();

		// initialize left panel
		m_leftPanel.setPreferredSize(new Dimension(m_leftWidth, m_appletHeight
				- m_topPanelHeight));
		m_leftPanel.setBackground(mainBgColor);
		add(m_leftPanel, BorderLayout.WEST);

		// initialize input bar
		iniInputBar();

		// initialize right panel
		m_rightPanel.setPreferredSize(new Dimension(m_rightWidth,
				m_appletHeight));
		m_rightPanel.setBackground(mainBgColor);
		add(m_rightPanel, BorderLayout.EAST);
	}

	private JTextField[] m_addFields = new JTextField[m_nFloors];
	private JPanel m_inputBar = new JPanel();

	private void iniInputBar() {
		m_inputBar.setPreferredSize(new Dimension(m_inputBarWidth,
				m_appletHeight - m_topPanelHeight));
		m_inputBar.setBorder(new EmptyBorder(30, 10, m_marginBottom, 10));
		m_inputBar.setBackground(inputBarBgColor);
		add(m_inputBar, BorderLayout.CENTER);

		m_inputBar.setLayout(new GridLayout(m_nFloors, 1, 10, 10));

		// add text fields
		for (int i = 0; i < m_nFloors; i++) {
			m_addFields[i] = new JTextField();
			m_inputBar.add(m_addFields[i]);
			m_addFields[i].addActionListener(m_inputBarTextFieldListener);
		}
	}

	private JPanel m_topPanel = new JPanel();

	private JLabel m_jlableUserComingInterval = new JLabel(
			"User Coming Inverval (seconds)");

	private JCheckBox m_randomCheck = new JCheckBox("Generate Random Tasks");

	private TaskRateSlider m_userComingInterval = new TaskRateSlider();

	private String[] taskGeneratingModes = TaskGenerator.getAllModeNames();
	private JComboBox comboBoxTaskGeneratingMode = new JComboBox(
			taskGeneratingModes);

	private void iniTopPanel() {
		m_topPanel.setPreferredSize(new Dimension(m_appletWidth,
				m_topPanelHeight));
		m_topPanel.setBorder(new EmptyBorder(10, 200, 10, 200));
		m_topPanel.setBackground(topPanelBgColor);
		add(m_topPanel, BorderLayout.NORTH);

		m_topPanel.setLayout(new GridLayout(2, 2, 100, 10));

		// user coming interval label
		m_jlableUserComingInterval.setBackground(m_topPanel.getBackground());
		m_topPanel.add(m_jlableUserComingInterval);

		// generate random tasks check box
		m_randomCheck.setBackground(m_topPanel.getBackground());
		m_topPanel.add(m_randomCheck);
		m_randomCheck.addActionListener(m_generateTaskCheckBoxListener);
		// m_randomCheck.doClick();

		// user coming interval slider
		m_userComingInterval.setBackground(m_topPanel.getBackground());
		m_topPanel.add(m_userComingInterval);
		m_userComingInterval.addChangeListener(m_userComingInterval);

		// task generating mode comboBox
		comboBoxTaskGeneratingMode.setBackground(Color.WHITE);
		m_topPanel.add(comboBoxTaskGeneratingMode);
		comboBoxTaskGeneratingMode
				.addActionListener(m_taskGeneratingModeComboBoxListener);
	}

	public void paint(Graphics g) {
		m_bufferGraphics.clearRect(0, 0, m_appletWidth, m_appletHeight);
		super.paint(m_bufferGraphics);

		m_bufferGraphics.setColor(Color.BLACK);
		_leftPartDrawer.drawLeftPart(m_bufferGraphics,
				m_leftElevator.getCurrentLevel(), m_leftTasks);

		_rightPartDrawer.drawRightPart(m_bufferGraphics,
				m_rightElevator.getCurrentLevel(), m_rightTasks,
				m_rightTaskQueueUtility);

		drawRatio(m_bufferGraphics);
		g.drawImage(m_offscreen, 0, 0, this);
	}

	private void drawRatio(Graphics g) {
		int totalLeft = _leftPartDrawer.getTotalDistance();
		int totalRight = _rightPartDrawer.getTotalDistance();
		String result = "Energy Saved: ";
		if (totalRight == 0 || totalRight - totalLeft <= 0)
			result += "unavailable";
		else {
			result += (totalRight - totalLeft) * 100 / totalRight;
			result += "%";
		}
		Font oringinal = g.getFont();
		Font big = new Font(null, 20, 20);
		g.setFont(big);
		g.drawString(result, 350, 580);
		g.setFont(oringinal);
	}

	/**
	 * Part 3: listeners and supporting classes
	 */

	private class TaskRateSlider extends JSlider implements ChangeListener {
		private static final long serialVersionUID = 123L;

		public TaskRateSlider() {
			super(JSlider.HORIZONTAL,
					IniParameters.userComingIntervalMin / 1000,
					IniParameters.userComingIntervalMax / 1000,
					IniParameters.userComingIntervalDefault / 1000);
			initial();
		}

		private void initial() {
			setMajorTickSpacing(1);
			setMinorTickSpacing(1);
			setPaintTicks(true);
			setPaintLabels(true);
		}

		@Override
		public void stateChanged(ChangeEvent e) {
			JSlider source = (TaskRateSlider) e.getSource();
			if (!source.getValueIsAdjusting()) {
				int delayInSeconds = source.getValue();
				m_taskGenerator.setInterDelay(delayInSeconds);
			}
		}

	}

	private ActionListener m_taskGeneratingModeComboBoxListener = new ActionListener() {
		public void actionPerformed(ActionEvent e) {
			JComboBox comboBoxTaskGeneratingMode = (JComboBox) e.getSource();
			String modeName = comboBoxTaskGeneratingMode.getSelectedItem()
					.toString();
			m_taskGenerator.changeMode(modeName);
		}
	};

	private ActionListener m_generateTaskCheckBoxListener = new ActionListener() {
		public void actionPerformed(ActionEvent e) {
			JCheckBox randomCheck = (JCheckBox) e.getSource();
			if (randomCheck.isSelected() == true)
				m_taskGenerator.startGenerating();
			else
				m_taskGenerator.stopGenerating();
		}
	};

	private ActionListener m_inputBarTextFieldListener = new ActionListener() {
		public void actionPerformed(ActionEvent e) {
			for (int i = 0; i < m_nFloors; i++) {
				if (!m_addFields[i].getText().trim().equals("")) {
					String str = m_addFields[i].getText().trim();
					int source = m_nFloors - i - 1;

					try {
						int dest = Integer.parseInt(str);
						if (dest != source && 0 <= dest && dest < m_nFloors) {
							m_leftTasks.addTask(source, dest);
							m_rightTaskQueueUtility
									.addToTaskQueue(source, dest);
						}
					} catch (Exception ex) {
					}

					m_addFields[i].setText("");
				}
			}
		}
	};
}
